/**
 * losenote.com Inc.
 * Copyright (c) 2013-2013 All Rights Reserved.
 */
package com.losenote.base.template;

import org.apache.log4j.Logger;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.losenote.base.LnException;
import com.losenote.enums.LnResultCodeEnum;
import com.losenote.service.result.LnResult;

/**
 * 编程式事务模板
 * 
 * @author danjingyu
 * @version $Id: ServiceTemplateImpl.java, v 0.1 2013-4-21 下午1:41:48 danjingyu
 *          Exp $
 */
public class ServiceTemplateImpl implements ServiceTemplate {

	/** 日志 */
	private static final Logger logger = Logger
			.getLogger(ServiceTemplateImpl.class);

	/** 事务模板 */
	private TransactionTemplate transactionTemplate;

	/**
	 * @see com.alipay.csaccurate.biz.service.impl.template.ServiceTemplate#executeWithoutTransaction(java.lang.Class,
	 *      com.alipay.csaccurate.biz.service.impl.template.ServiceCallback)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public <T> T executeWithoutTransaction(Class<? extends LnResult> clazz,
			ServiceCallback action) {

		if (logger.isInfoEnabled()) {
			logger.info("进入无事务服务模板");
		}

		LnResult result = null;
		try {

			result = clazz.newInstance();

			{
				// 执行校验
				action.check();
			}

			// 执行处理逻辑
			{
				result = action.executeService();
			}

			if (result == null || !(result instanceof LnResult)) {

				throw new LnException(LnResultCodeEnum.LOGIC_ERROR);
			}

		} catch (LnException e) {

			// 业务异常捕获
			logger.warn("无事务服务模板-业务异常：[" + e.getCode() + "](" + e.getMessage()
					+ ")", e);

			result.setCode(e.getCode());
			result.setMessage(e.getMessage());
			return (T) result;

		} catch (Throwable e2) {

			// 系统异常捕获
			logger.error("无事务服务模板-系统异常：", e2);

			result.setCode(LnResultCodeEnum.SYSTEM_FAILURE.getCode());
			result.setMessage(LnResultCodeEnum.SYSTEM_FAILURE.getDescription());
			return (T) result;
		}
		if (logger.isInfoEnabled()) {
			logger.info("退出无事务服务模板,result=" + result);
		}

		return (T) result;
	}

	/**
	 * @see com.alipay.csaccurate.biz.service.impl.template.ServiceTemplate#execute(java.lang.Class,
	 *      com.alipay.csaccurate.biz.service.impl.template.ServiceCallback)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public <T> T execute(final Class<? extends LnResult> clazz,
			final ServiceCallback action) {

		if (logger.isInfoEnabled()) {
			logger.info("进入服务模板");
		}

		T acResult = (T) transactionTemplate.execute(new TransactionCallback() {
			/**
			 * @see org.springframework.transaction.support.TransactionCallback#doInTransaction(org.springframework.transaction.TransactionStatus)
			 */
			@Override
			public Object doInTransaction(TransactionStatus status) {

				LnResult result = new LnResult();

				try {

					result = clazz.newInstance();

					{
						// 执行校验逻辑
						action.check();
					}

					{
						// 执行处理逻辑
						result = action.executeService();
					}

					// 返回值异常处理
					if (result == null || !(result instanceof LnResult)) {
						throw new LnException(LnResultCodeEnum.LOGIC_ERROR);
					}

				} catch (LnException e) {

					// 业务异常捕获
					{
						logger.warn(
								"事务服务模板-业务异常：[" + e.getCode() + "]("
										+ e.getMessage() + ")", e);
						status.setRollbackOnly();
					}

					result.setCode(e.getCode());
					result.setMessage(e.getMessage());
					return result;

				} catch (Throwable e2) {

					// 系统异常捕获
					logger.error("服务模板-系统异常：", e2);
					status.setRollbackOnly();

					result.setCode(LnResultCodeEnum.SYSTEM_FAILURE.getCode());
					result.setMessage(LnResultCodeEnum.SYSTEM_FAILURE
							.getDescription());
					return result;
				}

				return result;
			}
		});

		if (logger.isInfoEnabled()) {
			logger.info("退出服务模板,result=" + acResult);
		}

		return acResult;
	}

	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
}
